package com.liuya.safe.entitle.handler;

import java.io.Serializable;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import com.liuya.common.exception.EntityExistException;
import com.liuya.common.ReflectUtil;
import com.liuya.common.StringUtil;
import com.liuya.safe.entitle.service.EntitleManagerService;
import com.liuya.safe.model.SafePrivilege;
import com.liuya.safe.model.SafeUser;
import com.liuya.safe.policy.service.QueryManagerService;
import com.liuya.safe.util.AuthUtil;
import com.liuya.safe.util.Factory;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.ValidationException;

import com.liuya.db.sql.xml.BusinessDataType;
import com.liuya.db.sql.xml.DefineVariable;
import com.liuya.db.sql.xml.UserCategory;
import com.liuya.db.sql.xml.UserCategoryType;
import com.liuya.safe.model.SafeDecisionEntitlement;
import com.liuya.entitle.DecisionEntitlementTestResult;

//@Component("decisionEntitlementHandler")
public class DecisionEntitlementHandler implements Serializable {
    private SafePrivilege privilege;
    private List decisionEntitlements = new ArrayList();
//    @Autowired
//    @Qualifier("queryManagerService")
//    private QueryManagerService queryManager;
//    @Autowired
//    @Qualifier("entitleManagerService")
//    private EntitleManagerService entitleManager;
    private String businessDataClass;

    public DecisionEntitlementHandler() {
    }

    public DecisionEntitlementHandler(SafePrivilege privilege, Collection entitlements) {
        this.privilege = privilege;
        this.decisionEntitlements.addAll(entitlements);
    }

//    public DecisionEntitlementHandler(SafePrivilege privilege, Collection entitlements, QueryManagerService queryManager, EntitleManagerService entitleManager) {
//        this.privilege = privilege;
//        this.decisionEntitlements.addAll(entitlements);
//        this.queryManager = queryManager;
//        this.entitleManager = entitleManager;
//    }

    public String getBusinessDataClass() {
        return businessDataClass;
    }

    public void setBusinessDataClass(String businessDataClass) {
        this.businessDataClass = businessDataClass;
    }

    public SafePrivilege getPrivilege() {
        return privilege;
    }

    public List getDecisionEntitlements() {
        return decisionEntitlements;
    }

    public void addEntitle(SafeDecisionEntitlement entitle) {
        decisionEntitlements.add(entitle);
    }

    public void updateEntitle(int index, SafeDecisionEntitlement entitle) {
        decisionEntitlements.set(index, entitle);
    }

    public void moveEntitle(int index, String direct) {
        int moveIndex = index;

        // change column with it
        int changeIndex = -1;
        if ("top".equals(direct)) {
            if (moveIndex != 0) {
                changeIndex = 0;
            }
        } else if ("up".equals(direct)) {
            if (moveIndex != 0) {
                changeIndex = moveIndex - 1;
            }
        } else if ("down".equals(direct)) {
            if (moveIndex != (decisionEntitlements.size() - 1)) {
                changeIndex = moveIndex + 1;
            }
        } else if ("bottom".equals(direct)) {
            if (moveIndex != (decisionEntitlements.size() - 1)) {
                changeIndex = decisionEntitlements.size() - 1;
            }
        }

        if (changeIndex != -1) {
            Object moveOne = decisionEntitlements.get(moveIndex);

            if ("top".equals(direct)) {
                decisionEntitlements.remove(moveIndex);
                decisionEntitlements.add(0, moveOne);
            } else if ("bottom".equals(direct)) {
                decisionEntitlements.remove(moveIndex);
                decisionEntitlements.add(decisionEntitlements.size(), moveOne);
            } else if ("up".equals(direct) || "down".equals(direct)) {
                Object changeOne = decisionEntitlements.get(changeIndex);

                decisionEntitlements.set(changeIndex, moveOne);
                decisionEntitlements.set(moveIndex, changeOne);
            }
        }
    }

    public void deleteEntitle(int index) {
        decisionEntitlements.remove(index);
    }

    public void save() throws EntityExistException {
        EntitleManagerService entitleManager = Factory.getEntitleManager("");
        Collection oldEntitles = entitleManager.getDecisionEntitlements(privilege.getId());

        // delete old entries
        for (Iterator iter = oldEntitles.iterator(); iter.hasNext();) {
            SafeDecisionEntitlement entitle = (SafeDecisionEntitlement) iter.next();
            entitleManager.deleteDecisionEntitlement(entitle.getId());
        }

        // add new entries
        for (Iterator iter = decisionEntitlements.iterator(); iter.hasNext();) {
            SafeDecisionEntitlement entitle = (SafeDecisionEntitlement) iter.next();
            entitleManager.addDecisionEntitlement(entitle);
        }
    }

    public String[] getTestContextFields() throws MarshalException, ValidationException {
        Set fields = new HashSet();
        QueryManagerService queryManager = Factory.getQueryManager("");

        for (Iterator iter = decisionEntitlements.iterator(); iter.hasNext();) {
            SafeDecisionEntitlement entitle = (SafeDecisionEntitlement) iter.next();

            String xmlContent = entitle.getBusinessData().getXmlContent();
            BusinessDataType bdt = BusinessDataType.unmarshal(new StringReader(xmlContent));
            DefineVariable[] defineVariables = bdt.getDefineVariable();
            AuthUtil.extractContextValueFields(defineVariables, queryManager, fields);

            xmlContent = entitle.getUserCategory().getXmlContent();
            UserCategoryType unmarshal;
            unmarshal = UserCategory.unmarshal(new StringReader(xmlContent));

            DefineVariable[] variables = unmarshal.getDefineVariable();
            AuthUtil.extractContextValueFields(variables, queryManager, fields);
        }

        return (String[]) fields.toArray(new String[0]);
    }

    public DecisionEntitlementTestResult run(Locale locale, SafeUser testUser, Map testCtx) {
        EntitleManagerService entitleManager = Factory.getEntitleManager("");
        DecisionEntitlementTestResult testDecisionEntitlement = entitleManager.testDecisionEntitlement(locale, privilege.getId(), decisionEntitlements, testUser, testCtx);
        return testDecisionEntitlement;
    }

    public String[] getTestBusinessDataFieldTypes() throws MarshalException, ValidationException {
        String[] fields = getTestBusinessDataFields();
        String[] types = new String[fields.length];

        if (!StringUtil.isEmpty(businessDataClass)) {
            String[][] reflectJavaBean = ReflectUtil.reflectJavaBean(businessDataClass);

            for (int i = 0; i < fields.length; i++) {
                String field = fields[i];

                for (int j = 0; j < reflectJavaBean.length; j++) {
                    String[] strings = reflectJavaBean[j];

                    if (strings[0].equals(field)) {
                        types[i] = strings[1];
                        j = reflectJavaBean.length;
                    }
                }
            }
        }

        return types;
    }

    public String[] getTestBusinessDataFields() throws MarshalException, ValidationException {
        Set fields = new HashSet();

        for (Iterator iter = decisionEntitlements.iterator(); iter.hasNext();) {
            SafeDecisionEntitlement entitle = (SafeDecisionEntitlement) iter.next();

            String xmlContent = entitle.getBusinessData().getXmlContent();
            BusinessDataType bdt = BusinessDataType.unmarshal(new StringReader(xmlContent));
            DefineVariable[] defineVariables = bdt.getDefineVariable();
            AuthUtil.extractBusinessDataFields(defineVariables, fields);
        }

        return (String[]) fields.toArray(new String[0]);
    }
}